home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
Plotter
/
PlotView.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
9KB
|
343 lines
/* PlotView.m -- Implementation file for the PlotView class */
#import "PlotView.h"
#import "drawingFuncs.h"
#import <objc/Storage.h>
#import <appkit/NXCursor.h>
#import <appkit/Application.h>
#import <appkit/Window.h>
#import <appkit/Cell.h>
#import <appkit/Pasteboard.h>
#import <NXCType.h>
#import <math.h>
#import <dpsclient/psops.h>
#import <dpsclient/wraps.h>
#import <stdlib.h>
#import <string.h>
extern float getNumber(NXStream *stream);
extern int getSeparator(NXStream *stream);
#define MAXNUMLENGTH 50
#define DEFAULTRADIUS 1.0
@implementation PlotView
- initFrame:(const NXRect *)frameRect
/*
* Initializes the new PlotView object. First, an initFrame: message is sent to
* super to initialize PlotView as a View. Next, the PlotView sets its own
* state -- that it is opaque and that the origin of its coordinate system lies in
* the center of its area. It then creates and initializes its associated objects,
* a Storage object, an NXCursor, and a Cell. Finally, it loads into the Window
* Server some PostScript procedures that it will use in drawing itself.
*/
{
NXPoint spot;
[super initFrame:frameRect];
[self setOpaque:YES];
[self setRadius:DEFAULTRADIUS];
[self translate:floor(frame.size.width/2) :floor(frame.size.height/2)];
points = [[Storage alloc] initCount:0 elementSize:sizeof(NXPoint) description:"{ff}"];
crossCursor = [NXCursor newFromImage:[NXImage newFromSection:"cross.tiff"]];
spot.x = spot.y = 7.0;
[crossCursor setHotSpot:&spot];
/*
* Normally, the next two message expressions would be combined, as:
* readOut = [[Cell alloc] initTextCell:""];
* but are here separated for clarity.
*/
readOut = [Cell alloc];
[readOut initTextCell:""];
[readOut setBezeled:YES];
loadPSProcedures();
return self;
}
- setDelegate:anObject
/*
* Sets the PlotView's delegate instance variable to the supplied object.
*/
{
delegate = anObject;
return self;
}
- drawSelf:(const NXRect *)rects :(int)rectCount
/*
* Draws the PlotView's background and axes. If there are any points,
* these are drawn too.
*/
{
unsigned int i;
NXPoint *aPoint;
if (rects == NULL) return self;
/* If we're printing, we need to load drawing procedures to printing context */
if (NXDrawingStatus != NX_DRAWING)
loadPSProcedures();
/* paint visible area white then draw axes */
PSsetgray(NX_WHITE);
NXRectFill(&rects[0]);
PSsetgray(NX_DKGRAY);
drawAxes(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
/* now take each point and draw it */
PSsetgray(NX_BLACK);
i = [points count];
while (i--) {
aPoint = (NXPoint *)[points elementAt:i];
drawCircle(aPoint->x, aPoint->y, radius);
}
return self;
}
- clear:sender
/*
* Clears the PlotView by emptying its Storage object of all points
* and then redisplaying the PlotView. This action is taken only if
* the PlotView's state requires it.
*/
{
if (needsClearing) {
[points empty];
[self display];
needsClearing = NO;
}
return self;
}
- sizeTo:(NXCoord)width :(NXCoord)height
/*
* Ensures that whenever the PlotView is resized, the origin of its
* coordinate system is repositioned to the center of its area.
*/
{
[super sizeTo:width :height];
[self setDrawOrigin:-floor(width/2) : -floor(height/2)];
return self;
}
- registerPoint:(NXPoint *)aPoint
/*
* Adds a point to the list the PlotView keeps in its Storage object.
*/
{
[points addElement:aPoint];
return self;
}
- mouseDown:(NXEvent *) theEvent
/*
* Responds to a message the system sends whenever the user presses the mouse
* button when the cursor is over the PlotView. The PlotView changes the
* cursor to a cross-hairs image and then starts asking for mouse-dragged or mouse-
* up events. As it receives mouse-dragged events, the PlotView updates the readOut
* text Cell with the cursor's coordinates. If the user releases the mouse
* button while the cursor is over the PlotView, the PlotView registers the
* point and then sends a message to its delegate notifying it of the new
* point.
*/
{
int looping = YES, oldMask;
NXPoint aPoint;
NXRect plotRect, cellRect;
char buffer[100];
[crossCursor set];
[self getBounds:&plotRect];
NXSetRect(&cellRect, plotRect.origin.x, plotRect.origin.y, 100.0, 20.0);
oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
[self lockFocus];
do {
aPoint = theEvent->location;
[self convertPoint:&aPoint fromView:nil];
sprintf(buffer, "(%d, %d)", (int)aPoint.x, (int)aPoint.y);
[readOut setStringValue:buffer];
[readOut drawInside:&cellRect inView:self];
[window flushWindow];
if (theEvent->type == NX_MOUSEUP) {
/* on mouse-up, register point, inform delegate, and clean up state */
[readOut setStringValue:""];
[readOut drawInside:&cellRect inView:self];
[window flushWindow];
if (NXPointInRect(&aPoint, &plotRect)) {
PSsetgray(NX_BLACK);
drawCircle(aPoint.x, aPoint.y, radius);
[window flushWindow];
[self registerPoint:&aPoint];
needsClearing = YES;
if (delegate && [delegate respondsTo:@selector(plotView:pointDidChange:)])
[delegate plotView:self pointDidChange:&aPoint];
}
looping = NO;
}
} while (looping && (theEvent=[NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK]));
[self unlockFocus];
[window setEventMask:oldMask];
[NXArrow set];
return self;
}
- setRadius:(float)aFloat
/*
* Sets the value for the radius of the PlotView's points.
*/
{
radius = aFloat;
return self;
}
- (float)radius
/*
* Returns the value for the radius of the PlotView's points.
*/
{
return radius;
}
- read:(NXTypedStream*)stream
/*
* Unarchives the PlotView. Initializes four of the PlotView's instance variables
* to the values stored in the stream.
*/
{
[super read:stream];
delegate = NXReadObject(stream);
NXReadTypes(stream, "@@@f", &points, &crossCursor, &readOut, &radius);
return self;
}
- write:(NXTypedStream*)stream
/*
* Archives the PlotView by writing its important instance variables to the stream.
*/
{
[super write:stream];
NXWriteObjectReference(stream, delegate);
NXWriteTypes(stream, "@@@f", &points, &crossCursor, &readOut, &radius);
return self;
}
- awake
/*
* Finishes initializing a PlotView that has just been unarchived (see the read: method).
*/
{
loadPSProcedures();
return [super awake];
}
- (const char*)inspectorName
{
return "PlotViewInspector";
}
- plot:sender
/*
* Responds to a plot: message by asking the PlotView's delegate for a stream
* containing the points to plot. It then extracts number pairs from the stream
* and creates NXPoint structures with them. For each structure it creates, the
* PlotView sends itself a registerPoint: message to add the point to its list of
* points. This simple parser ignores input it doesn't understand.
*/
{
int c, sign, retval;
float aNum;
NXPoint aPoint;
NXStream *stream;
BOOL processedLine = NO, gotFirst = NO, gotSecond = NO;
if (delegate && [delegate respondsTo:@selector(plotView:providePoints:)])
[delegate plotView:self providePoints:&stream];
NXSeek(stream, 0, NX_FROMSTART);
while ((c = NXGetc(stream)) != EOF){
sign = 1;
retval = getSeparator(stream);
if (retval == 1) {
c = NXGetc(stream);
} else if (retval == -1) {
break;
}
if (!NXIsDigit(c)) {
if ((c == '-') && NXIsDigit(c = NXGetc(stream))){
sign = -1;
} else {
while( (c != '\n') && (c != EOF)) {
c = NXGetc(stream);
processedLine = YES;
}
}
}
if (c == EOF)
break;
else if (processedLine) {
processedLine = NO;
continue;
}
aNum = getNumber(stream);
if (!gotFirst) {
aPoint.x = sign * aNum;
gotFirst = YES;
} else if (!gotSecond) {
aPoint.y = sign * aNum;
[self registerPoint:&aPoint];
gotFirst = gotSecond = NO;
}
}
[self display];
needsClearing = YES;
return self;
}
int getSeparator(NXStream *stream)
/*
* Removes white space, commas, and plus signs from between
* number pairs.
*/
{
int c, firstChar;
NXUngetc(stream);
c = firstChar = NXGetc(stream);
while (NXIsSpace(c) || (c == ',') || (c == '+'))
c = NXGetc(stream);
/* 1 = ate something; 0 = ate nothing; -1 means EOF */
if (c == firstChar)
return 0;
else if (c == EOF)
return -1;
NXUngetc(stream);
return 1;
}
float getNumber(NXStream *stream)
/*
* Composes a floating point number from a string of number
* characters.
*/
{
int c, i = 0;
char temp[MAXNUMLENGTH];
NXUngetc(stream);
c = NXGetc(stream);
while ((NXIsDigit(c) || (c == '.')) && (c != '\n') && (c != EOF)) {
temp[i++] = c;
c = NXGetc(stream);
}
NXUngetc(stream);
temp[i] = 0;
return (atof(temp));
}
@end